#include "catch.hpp"
#include "ACEtk.hpp"
#include <map>

using namespace njoy::ACEtk;

extern std::array< double, 90 > refIndVarcoherentFormFactor;
extern std::array< double, 90 > refCumulativeCoherentFormFactor;
extern std::array< double, 90 > refDifferentialCoherentFormFactor;


SCENARIO( "Test interpretation::EPRdata::Coherent" ){
  auto table = Table( njoy::utility::slurpFileToMemory( "1000.14p" ) );

  GIVEN( "An ACE Table for 1000.14p" ){
    const auto eprdata = interpretation::EPR( std::move(table) );

    WHEN( "Querying for the energy grid for the coherent scattering cross sections" ) {
      const std::map< int, double > referencePhotonEnergies{
	{   0, 1.000000000000E-06 },
	{  64, 8.013002999974E-06 },
	{ 129, 1.017127000001E-05 },
	{ 194, 1.167710000005E-05 },
	{ 259, 1.249504000002E-05 },
	{ 324, 2.788451999999E-05 },
	{ 389, 3.101247999991E-03 },
	{ 454, 7.413102000002E-01 },
        { 519, 2.745299999992E+00 },
	{ 584, 7.943300000026E+01 },
	{ 646, 1.000000000000E+05 } };
      
      const auto photonEnergies = eprdata.coherent().energies();

      for ( const auto& pair : referencePhotonEnergies ){
	const auto index = pair.first;
	const auto reference = pair.second;
	REQUIRE( photonEnergies[ index ].value == Approx( reference ).epsilon( 1e-8 ) );
      }
      
      using Energy_t = decltype( photonEnergies.front() );
      using Expected_t = dimwits::Quantity< dimwits::Mega< dimwits::ElectronVolt > >;
      constexpr bool same_v = std::is_same<Energy_t, Expected_t>::value;
      REQUIRE( same_v );      
    }

    WHEN( "Querying for the coherent scattering cross sections" ){
      const std::map< int, double > referenceCoherentXS{
	{   0, 9.887553000014E-06 },
	{  65, 3.361804999998E-01 },
	{ 130, 4.768264000007E+02 },
	{ 195, 1.769341000000E-01 },
	{ 260, 1.616027000000E+00 },
	{ 325, 1.036825798528E+00 },
	{ 390, 2.587707888495E-01 },
	{ 455, 7.331701968226E-06 },
	{ 520, 5.862947790958E-07 },
	{ 585, 7.228371741121E-10 },
	{ 646, 4.626159999988E-16 } };
      
      const auto coherentScatteringXS = eprdata.coherent().crossSection();
      
      for ( const auto& pair : referenceCoherentXS ){
	const auto index = pair.first;
	const auto reference = pair.second;
	REQUIRE( coherentScatteringXS[ index ].value == Approx( reference ) );
      }

      using XS_t = decltype( coherentScatteringXS.front() );
      using Expected_t = dimwits::Quantity< dimwits::Barn >;
      constexpr bool same_v = std::is_same<XS_t, Expected_t>::value;
      REQUIRE( same_v );            

    }
    
    const auto cohff = eprdata.coherent().formFactors();
    WHEN( "Querying for the independant variable for the photon coherent form factors" ) {
      auto var = cohff.scatteringCosines();
      auto compairs = ranges::view::zip( refIndVarcoherentFormFactor, var );
      for( const auto pair : compairs ) {
	REQUIRE( pair.first == Approx( pair.second ) );
      }
    }

    WHEN( "Querying for the cumulative coherent form factors" ) {
      const auto cumulative = cohff.cumulative();
      const auto compairs = ranges::view::zip( refCumulativeCoherentFormFactor, cumulative );
      for( const auto pair : compairs ) {
	REQUIRE( pair.first == Approx( pair.second ) );
      }
    }
    
    WHEN( "Querying for the differential coherent form factors" ) {
      const auto differential = cohff.differential();
      const auto compairs = ranges::view::zip( refDifferentialCoherentFormFactor, differential );
      for( const auto pair : compairs ) {
	REQUIRE( pair.first == Approx( pair.second ) );
      }
    }
  }
}

std::array< double, 90 > refIndVarcoherentFormFactor = {{
    0.000000000000E+00, 1.000000000000E-03, 5.000000000000E-03,
    1.000000000000E-02, 1.500000000000E-02, 2.000000000000E-02,
    2.500000000000E-02, 3.000000000000E-02, 3.750000000000E-02,
    4.000000000000E-02, 4.750000000000E-02, 5.000000000000E-02,
    5.875000000000E-02, 6.625000000000E-02, 7.000000000000E-02,
    7.875000000000E-02, 8.000000000000E-02, 8.625000000000E-02,
    9.000000000000E-02, 9.750000000000E-02, 1.000000000000E-01,
    1.062500000000E-01, 1.156300000000E-01, 1.250000000000E-01,
    1.359400000000E-01, 1.453100000000E-01, 1.500000000000E-01,
    1.609400000000E-01, 1.703100000000E-01, 1.750000000000E-01,
    1.875000000000E-01, 2.000000000000E-01, 2.125000000000E-01,
    2.218800000000E-01, 2.289100000000E-01, 2.359400000000E-01,
    2.429700000000E-01, 2.500000000000E-01, 2.625000000000E-01,
    2.718800000000E-01, 2.789100000000E-01, 2.906300000000E-01,
    2.929700000000E-01, 3.000000000000E-01, 3.179700000000E-01,
    3.250000000000E-01, 3.330100000000E-01, 3.497600000000E-01,
    3.625000000000E-01, 3.677000000000E-01, 3.892300000000E-01,
    4.000000000000E-01, 4.250000000000E-01, 4.437500000000E-01,
    4.500000000000E-01, 4.718800000000E-01, 5.000000000000E-01,
    5.250000000000E-01, 5.625000000000E-01, 6.000000000000E-01,
    6.500000000000E-01, 7.000000000000E-01, 7.500000000000E-01,
    8.000000000000E-01, 8.750000000000E-01, 9.000000000000E-01,
    1.000000000000E+00, 1.125000000000E+00, 1.250000000000E+00,
    1.437500000000E+00, 1.500000000000E+00, 1.750000000000E+00,
    2.000000000000E+00, 2.500000000000E+00, 3.000000000000E+00,
    3.500000000000E+00, 4.000000000000E+00, 5.000000000000E+00,
    6.000000000000E+00, 7.000000000000E+00, 8.000000000000E+00,
    1.000000000000E+01, 1.500000000000E+01, 2.000000000000E+01,
    5.000000000000E+01, 8.000000000000E+01, 1.000000000000E+02,
    1.000000000000E+03, 1.000000000000E+06, 1.000000000000E+09 }};

std::array< double, 90 > refCumulativeCoherentFormFactor = {{
    0.000000000000E+00, 1.000000000000E-06, 2.498070484430E-05,
    9.974598658020E-05, 2.238054743310E-04, 3.963438049760E-04,
    6.162353622510E-04, 8.820587621180E-04, 1.362903276820E-03,
    1.544272134970E-03, 2.146951699350E-03, 2.366637726330E-03,
    3.201832749560E-03, 3.992472751970E-03, 4.410600395240E-03,
    5.435375809830E-03, 5.586942941720E-03, 6.360260387520E-03,
    6.835507680840E-03, 7.804854417450E-03, 8.132629709020E-03,
    8.958385028820E-03, 1.020584377160E-02, 1.144920382010E-02,
    1.287886462980E-02, 1.407228434750E-02, 1.465598029220E-02,
    1.597324195550E-02, 1.704810505420E-02, 1.756628130530E-02,
    1.887663666280E-02, 2.008342525890E-02, 2.118578128230E-02,
    2.194570721290E-02, 2.247841439640E-02, 2.298044786520E-02,
    2.345277687900E-02, 2.389652794540E-02, 2.461823627600E-02,
    2.510720519310E-02, 2.544612639830E-02, 2.596207210520E-02,
    2.605821262660E-02, 2.633397132680E-02, 2.695612989860E-02,
    2.717059415130E-02, 2.739694498890E-02, 2.781405047730E-02,
    2.808663768680E-02, 2.818804644310E-02, 2.855424020510E-02,
    2.870924697360E-02, 2.900913842900E-02, 2.918897143740E-02,
    2.924174308570E-02, 2.940236559080E-02, 2.956361281050E-02,
    2.967418962870E-02, 2.979758259240E-02, 2.988470056980E-02,
    2.996341569220E-02, 3.001459969810E-02, 3.004852149380E-02,
    3.007141358250E-02, 3.009308052880E-02, 3.009808411360E-02,
    3.011142479370E-02, 3.011967705090E-02, 3.012368161280E-02,
    3.012639603930E-02, 3.012687951530E-02, 3.012790733900E-02,
    3.012829306600E-02, 3.012853134980E-02, 3.012858917360E-02,
    3.012860700450E-02, 3.012861352260E-02, 3.012861746610E-02,
    3.012861840420E-02, 3.012861869030E-02, 3.012861879420E-02,
    3.012861885670E-02, 3.012861887700E-02, 3.012861887860E-02,
    3.012861887900E-02, 3.012861887900E-02, 3.012861887900E-02,
    3.012861887900E-02, 3.012861887900E-02, 3.012861887900E-02 }};

std::array< double, 90 > refDifferentialCoherentFormFactor = {{
    1.000000000000E+00, 1.000000000000E+00, 9.994500000000E-01,
    9.977900000000E-01, 9.950400000000E-01, 9.912100000000E-01,
    9.863200000000E-01, 9.803900000000E-01, 9.695910000000E-01,
    9.655400000000E-01, 9.518880000000E-01, 9.469400000000E-01,
    9.278400000000E-01, 9.096010000000E-01, 8.998700000000E-01,
    8.757760000000E-01, 8.721610000000E-01, 8.537270000000E-01,
    8.423900000000E-01, 8.187930000000E-01, 8.108200000000E-01,
    7.903800000000E-01, 7.590290000000E-01, 7.271200000000E-01,
    6.894680000000E-01, 6.572700000000E-01, 6.413000000000E-01,
    6.043200000000E-01, 5.733520000000E-01, 5.581200000000E-01,
    5.185450000000E-01, 4.807900000000E-01, 4.449150000000E-01,
    4.193120000000E-01, 4.009390000000E-01, 3.832090000000E-01,
    3.661360000000E-01, 3.497500000000E-01, 3.221710000000E-01,
    3.028140000000E-01, 2.890650000000E-01, 2.674080000000E-01,
    2.632700000000E-01, 2.512700000000E-01, 2.229550000000E-01,
    2.128040000000E-01, 2.017980000000E-01, 1.806930000000E-01,
    1.662140000000E-01, 1.606750000000E-01, 1.397670000000E-01,
    1.304500000000E-01, 1.113530000000E-01, 9.908660000000E-02,
    9.533620000000E-02, 8.345640000000E-02, 7.059600000000E-02,
    6.105480000000E-02, 4.943010000000E-02, 4.032700000000E-02,
    3.109610000000E-02, 2.428600000000E-02, 1.919230000000E-02,
    1.533600000000E-02, 1.116450000000E-02, 1.009200000000E-02,
    6.881600000000E-03, 4.449490000000E-03, 2.994900000000E-03,
    1.759020000000E-03, 1.493900000000E-03, 8.230890000000E-04,
    4.890600000000E-04, 2.035500000000E-04, 9.902300000000E-05,
    5.373400000000E-05, 3.160600000000E-05, 1.299800000000E-05,
    6.282400000000E-06, 3.395600000000E-06, 1.992200000000E-06,
    8.168200000000E-07, 1.615100000000E-07, 5.112000000000E-08,
    1.309200000000E-09, 1.997700000000E-10, 8.182800000000E-11,
    8.182900000000E-15, 8.182900000000E-27, 8.182900000000E-39 }};
